package com.ct.ecommerce.order.service;


import com.ct.ecommerce.api.goods.client.GoodsService;
import com.ct.ecommerce.api.goods.dto.GoodsDTO;
import com.ct.ecommerce.api.idgen.client.IdGeneratorService;
import com.ct.ecommerce.api.idgen.client.SnGeneratorService;
import com.ct.ecommerce.api.order.client.OrderService;
import com.ct.ecommerce.api.order.dto.OrderDTO;
import com.ct.ecommerce.api.uc.client.AccountService;
import com.ct.ecommerce.api.uc.dto.AccountDTO;
import com.ct.ecommerce.framework.core.BeanCopierUtils;
import com.ct.ecommerce.framework.enums.ECommerceCodeEnum;
import com.ct.ecommerce.framework.enums.OrderStatusEnum;
import com.ct.ecommerce.framework.enums.SerialNumberTypeEnumEnum;
import com.ct.ecommerce.framework.exception.CastException;
import com.ct.ecommerce.order.dao.entity.OrderEntity;
import com.ct.ecommerce.order.dao.entity.OrderItemEntity;
import com.ct.ecommerce.order.dao.mapper.OrderItemMapper;
import com.ct.ecommerce.order.dao.mapper.OrderMapper;
import io.seata.spring.annotation.GlobalTransactional;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;

/**
 * @author changtong
 * @since 2021/5/23
 */
@DubboService
@Slf4j
public class OrderServiceImpl implements OrderService {


    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderItemMapper orderItemMapper;
    @DubboReference
    private IdGeneratorService idGeneratorService;
    @DubboReference
    private SnGeneratorService snGeneratorService;
    @DubboReference
    private AccountService accountService;
    @DubboReference
    private GoodsService goodsService;


    @Override
    @GlobalTransactional
    public Long createOrder(OrderDTO order) {

        //获取用户账户信息
        AccountDTO userAccount = accountService.findUserAccount(order.getUserId());
        log.info("获取 用户资金账户信息 => {}", userAccount);
        buildCreateOrder(order);

        OrderEntity orderEntity = BeanCopierUtils.copyProperties(order,OrderEntity.class);
        List<OrderItemEntity> orderItems
            = BeanCopierUtils.copyPropertiesOfList(order.getItems(),OrderItemEntity.class);

        if (userAccount.getAmount().compareTo(orderEntity.getAmount()) < 0) {
            CastException.cast(ECommerceCodeEnum.USER_NOT_ENOUGH_BALANCE);
        }

        //插入订单表
        orderMapper.insert(orderEntity);
        orderItems.forEach(orderItemMapper::insert);
        List<GoodsDTO> deductGoodsStock = orderItems.stream().map(i -> {
            GoodsDTO goods = new GoodsDTO();
            goods.setId(i.getGoodsId());
            //保存需要扣减的库存数量
            goods.setStock(i.getQuantity());
            return goods;
        }).collect(Collectors.toList());
        //扣减库存
        goodsService.deductGoodsStock(deductGoodsStock);
        //扣减账户金额
        accountService.deductAccountAmount(order.getUserId(), orderEntity.getAmount());

        return orderEntity.getId();
    }



    private void buildCreateOrder(OrderDTO order) {
        Timestamp now = new Timestamp(System.currentTimeMillis());
        Long pk = idGeneratorService.get();
        String sn = snGeneratorService.get(SerialNumberTypeEnumEnum.OrderSerialNumber.getValue());
        if (Objects.isNull(order.getFreight())) {
            order.setFreight(BigDecimal.ZERO);
        }
        order.setId(pk);
        order.setSn(sn);
        order.setCreateTime(now);
        order.setCreatorId(order.getUserId());
        order.setModifierId(order.getUserId());
        order.setOrderStatus(OrderStatusEnum.ToBePaid.getValue());

        //构建商品数据
        order.getItems().forEach(item->{
            Long goodsId = item.getGoodsId();
            GoodsDTO goods = goodsService.findGoodsById(goodsId);
            //判断是否大于库存
            if (item.getQuantity().compareTo(goods.getStock()) > 0) {
                CastException.cast(ECommerceCodeEnum.GOODS_NUM_NOT_ENOUGH);
            }
            item.setBrandName(goods.getBrandName());
            item.setGoodsName(goods.getName());
            item.setMainImage(goods.getMainImage());
            item.setPrice(goods.getSalesPrice());
            item.setOrderId(pk);
        });

        //价格计算
        BigDecimal goodsPrice = order.getItems().stream().map(i -> i.getPrice().multiply(i.getQuantity()))
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal amount = goodsPrice.add(order.getFreight());
        order.setAmount(amount);

    }
}
